package com.spotalog.server.service.rest;

import java.net.URI;

import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import com.google.appengine.api.search.Cursor;
import com.spotalog.server.service.Service;
import com.spotalog.shared.exceptions.NotFoundException;
import com.spotalog.shared.model.DatastoreObject;

/**
 * 
 * @author seandoyle
 * 
 * @param <T>
 *            <b>Must be Serializable by Jersey</b>
 */
public abstract class RestService<T extends DatastoreObject> {
	private final Service<T> service;
	private Cursor.Builder cursors;

	@Inject
	protected RestService(Service<T> service) {
		this.service = service;
	}

	protected Cursor safeCursor(String cursorString) {
		Cursor cursor = null;
		try {
			cursor = this.cursors.build(cursorString);
		} catch (Exception ex) {
		}
		return cursor;
	}

	@Inject
	protected void setCursorBuilder(Cursor.Builder cursors) {
		this.cursors = cursors;
	}

	@GET
	@Path("{key}")
	@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	public T getEntity(@PathParam("key") long key) throws NotFoundException {
		return this.service.readSafe(key);
	}

	@POST
	@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	public Response createEntity(T entity) {
		T upserted = this.service.upsert(entity);
		return Response.created(URI.create(String.valueOf(upserted.getId())))
				.entity(new GenericEntity<T>(entity) {
				}).build();
	}

	@PUT
	@Path("{key}")
	@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	public T updateEntity(@PathParam("key") long key, T entity)
			throws NotFoundException {
		this.service.read(key); // verifies that the entity with the key exists
		entity.setId(key);
		return this.service.upsert(entity);
	}

	@DELETE
	@Path("{key}")
	public void deleteEntity(@PathParam("key") long key) {
		this.service.delete(key);
	}
}
